// Copyright 2007 Google Inc. All Rights Reserved.

var DateRange = function(begin, end) {
  this.begin = begin;
  this.end = end;
}
DateRange.prototype = {
  getBegin: function() {
    return this.begin;
  },
  getEnd: function() {
    return this.end;
  },
  toParam: function() {
    return this._formatDate(this.begin) + "-" + this._formatDate(this.end);
  },
  toString: function() {
    return "[DateRange " + this.begin + " - " + this.end + "]";
  },
  _formatDate: function(date) {
    var YYYY = date.getFullYear();
    var MM = date.getMonth() + 1;
    if (MM < 10) {
      MM = "0" + MM;
    }
    var DD = date.getDate();
    if (DD < 10) {
      DD = "0" + DD;
    }
    return "" + YYYY + MM + DD;
  }
}

Flash.Serializers.add({
  serializes: function(value) {
    return (value instanceof DateRange);
  },
  serialize: function(builder, dateRange) {
    return builder.wrap("dr", function() {
      return builder.serialize(dateRange.begin) + builder.serialize(dateRange.end);
    });
  }
});

var DateInputView = function(dateInputInterfaceProxy, localeString, errorMessage) {
  this.proxy = dateInputInterfaceProxy;
  this.dateParser = DateInputView.createDateParser(localeString);
  this.errorMessage = errorMessage;

  this.loading = document.getElementById("f_dateInputLoading");
  this.flash = document.getElementById("f_dateInputFlash");
  this.form = document.getElementById("f_dateInputForm");
  this.primaryBeginField = document.getElementById("f_primaryBegin");
  this.primaryEndField = document.getElementById("f_primaryEnd");
  this.comparisonBeginField = document.getElementById("f_comparisonBegin");
  this.comparisonEndField = document.getElementById("f_comparisonEnd");
  this.primaryBeginFocus = document.getElementById("f_primaryBeginFocus");
  this.primaryEndFocus = document.getElementById("f_primaryEndFocus");
  this.comparisonBeginFocus = document.getElementById("f_comparisonBeginFocus");
  this.comparisonEndFocus = document.getElementById("f_comparisonEndFocus");
  this.comparisonEnabledCheckbox = document.getElementById("f_comparisonEnabledCheckbox");
  this.comparisonInputs = document.getElementById("f_comparisonInputs");
  this.applyButton = document.getElementById("f_apply");
  this.cancelButton = document.getElementById("f_cancel");
  this.dateRangeLengthNotice = document.getElementById("f_dateRangeLengthNotice");
  this.compareOptions = new Dropdown("f_comparison_label");

  this.lastValidPrimary = null;
  this.lastValidPrimaryLength = null;
  this.lastValidComparison = null;
  this.lastValidComparisonLength = null;
  this.currentFocus = null;

  this.windowHasLoaded = false;
  goog.events.listen(window, "load", function() {
    self.windowHasLoaded = true;
    self.hideLoadingMessage();
    if (self.displayed) {
      self.initFunction();
    }
  });  

  this.displayed = false;

  this.initializedFlash = false;

  this.form.style.display = "none";

  var self = this;
  var proxy = this.proxy;

  this.doNothingFunction = function() { return false; };
  this.applyFunction     = function() { proxy.sendMessage("applyDates"); return false; };
  this.cancelFunction    = function() { self.compareOptions.reset(); proxy.sendMessage("cancelDateChanges"); return false; };

  this.primaryBeginField.onclick    = function() { proxy.sendMessage("focusPrimaryBegin"); }
  this.primaryEndField.onclick      = function() { proxy.sendMessage("focusPrimaryEnd"); }
  this.comparisonBeginField.onclick = function() { proxy.sendMessage("focusComparisonBegin"); }
  this.comparisonEndField.onclick   = function() { proxy.sendMessage("focusComparisonEnd"); }

  this.primaryBeginField.onchange = this.primaryEndField.onchange = function() { 
    var begin = self.readDateFrom(self.primaryBeginField);
    var end = self.readDateFrom(self.primaryEndField);
    if (begin && end) {
      proxy.sendMessage("setPrimaryDateRange", new DateRange(begin, end)); 
    } else {
      self.messageBadInput();
      self.setPrimaryDateRange(
        self.lastValidPrimary, 
        self.lastValidPrimaryLength
      );
    }
  }

  this.comparisonBeginField.onchange = this.comparisonEndField.onchange = function() { 
    var begin = self.readDateFrom(self.comparisonBeginField);
    var end = self.readDateFrom(self.comparisonEndField);
    if (begin && end) {
      proxy.sendMessage("setComparisonDateRange", new DateRange(begin, end)); 
    } else {
      self.messageBadInput();
      self.setComparisonDateRange(
        self.lastValidComparison, 
        self.lastValidComparisonLength
      );
    }
  }

  if (this.comparisonEnabledCheckbox) {
    this.comparisonEnabledCheckbox.onclick = function() {
      if (this.checked) {
        proxy.sendMessage("enableComparisonDateRange");
        self.compareOptions.setOption("DATE_RANGE");
      } else {
        proxy.sendMessage("disableComparisonDateRange");
        self.compareOptions.setOption("AVERAGE");
      }
    }
  }
  
}
DateInputView.prototype = {

  initFunction: function() {

    this.displayed = true;

    if (this.windowHasLoaded && !this.initializedFlash) {
      this.proxy.sendMessage("initialize");
      this.initializedFlash = true;
    }
  },

  initialize: function() {
    this.hideLoadingMessage();
    this.form.style.display = "block";
  },
  
  hideLoadingMessage: function() {
    this.loading.style.display = "none";    
  },

  onApply: function(primaryDateRange, comparisonDateRange) {
    if (primaryDateRange && comparisonDateRange) {
      VisualizationModule.changeDateRangeAndComparisonDateRange(
        primaryDateRange.toParam(), comparisonDateRange.toParam());
    } else if (primaryDateRange) {
      VisualizationModule.changeDateRangeAndComparisonType(primaryDateRange.toParam(),
        this.compareOptions.selectedValue.toLowerCase());
    }
    this.compareOptions.setStartValue(this.compareOptions.selectedValue);

    goog.analytics.Menu.toggle("f_date_range", "f_date_range_options",
    goog.analytics.MenuType.CALENDAR);
    goog.analytics.Menu.clear("f_date_range", "f_date_range_options",
    goog.analytics.MenuType.CALENDAR);
  },


  setPrimaryDateRange: function(dateRange, length) {
    this.primaryBeginField.value = this.formatDate(dateRange.getBegin());
    this.primaryEndField.value = this.formatDate(dateRange.getEnd());
    this.lastValidPrimary = dateRange;
    this.lastValidPrimaryLength = length;
    this.needsToApply();
    this.showAlertIfDateRangeLengthsDiffer();
  },
  setComparisonDateRange: function(dateRange, length) {
    this.comparisonBeginField.value = this.formatDate(dateRange.getBegin());
    this.comparisonEndField.value = this.formatDate(dateRange.getEnd());
    this.lastValidComparison = dateRange;
    this.lastValidComparisonLength = length;
    this.enableComparisonDateRange();
    this.showAlertIfDateRangeLengthsDiffer();
  },
  disableComparisonDateRange: function() {
    if (this.comparisonEnabledCheckbox) {
      this.comparisonEnabledCheckbox.checked = false;
    }
    this.comparisonBeginField.disabled = true;
    this.comparisonEndField.disabled = true;
    this.comparisonBeginField.value = "";
    this.comparisonEndField.value = "";
    this.comparisonInputs.style.display = "none";
    this.lastValidComparison = null;
    this.lastValidComparisonLength = null;
    this.showAlertIfDateRangeLengthsDiffer();
    this.needsToApply();
  },
  enableComparisonDateRange: function() {
    if (this.comparisonEnabledCheckbox) {
      this.comparisonEnabledCheckbox.checked = true;
    }
    this.comparisonBeginField.disabled = false;
    this.comparisonEndField.disabled = false;
    this.comparisonInputs.style.display = "block";
    this.needsToApply();
  },

  applyDates: function() {
    this.onApply(this.lastValidPrimary, this.lastValidComparison);
    this.doesNotNeedToApply();
  },
  cancelDateChanges: function() {
    if (this.compareOptions.startValue == this.compareOptions.selectedValue) {
      this.doesNotNeedToApply();
    }
  },

  focusPrimaryBegin: function() {
    this.focusOnly(this.primaryBeginFocus, "left");
  },
  focusPrimaryEnd: function() {
    this.focusOnly(this.primaryEndFocus, "right");
  },
  focusComparisonBegin: function() {
    this.focusOnly(this.comparisonBeginFocus, "left");
  },
  focusComparisonEnd: function() {
    this.focusOnly(this.comparisonEndFocus, "right");
  },

  handlePrimaryDateRangeValidationError: function(resetDateRange, length) {
    this.messageValidationError();
    this.setPrimaryDateRange(resetDateRange, length);
  },

  handleComparisonDateRangeValidationError: function(resetDateRange, length) {
    this.messageValidationError();
    this.setComparisonDateRange(resetDateRange, length);
  },
  
  messageValidationError: function() {
    alert(this.errorMessage);
    this.reFocus();
  },
  
  messageBadInput: function() {
    alert(this.errorMessage);
    this.reFocus();
  },
  
  needsToApply: function() {
    this.form.onsubmit = this.applyFunction;
    this.applyButton.disabled = false;
    this.cancelButton.onclick = this.cancelFunction;
    this.cancelButton.className = "enabled";
  },
  
  doesNotNeedToApply: function() {
    this.form.onsubmit = this.doNothingFunction;
    this.applyButton.disabled = true;
    this.cancelButton.onclick = this.doNothingFunction;
    this.cancelButton.className = "disabled";
  },
  
  focusOnly: function(focusedField, side, opt_select) {
    this.primaryBeginFocus.className    = "focus_indicator left disabled";
    this.primaryEndFocus.className      = "focus_indicator right disabled";
    this.comparisonBeginFocus.className = "focus_indicator left disabled";
    this.comparisonEndFocus.className   = "focus_indicator right disabled";
    focusedField.className = "focus_indicator " + side + " enabled";
    if (opt_select) {
      var input = focusedField.getElementsByTagName("input")[0];
      setTimeout(function() {
        try {
          input.focus();
          input.select();
        } catch(e) {}
      }, 50);
    }
    this.currentFocus = [focusedField, side];
  },
  
  reFocus: function() {
    if (this.currentFocus) {
      this.focusOnly(this.currentFocus[0], this.currentFocus[1], true);
    }
  },
  
  dateRangeLengthsDiffer: function() {
    if (this.lastValidPrimaryLength && this.lastValidComparisonLength) {
      return Math.abs(this.lastValidPrimaryLength - this.lastValidComparisonLength) != 0;
    } else {
      return false;
    }
  },
  
  showAlertIfDateRangeLengthsDiffer: function() {
    if (this.dateRangeLengthsDiffer()) {
      this.dateRangeLengthNotice.style.display = "block";
    } else {
      this.dateRangeLengthNotice.style.display = "none";
    }
  },
  
  readDateFrom: function(textField) {
    return this.parseDate(textField.value);
  },
  
  formatDate: function(date) {
    return this.dateParser.format(date);
  },
  
  parseDate: function(date) {
    return this.dateParser.parse(date);
  },

  setCompareOption: function(value) {
    this.compareOptions.setOption(value);
  
    if (value == "DATE_RANGE") {
      this.proxy.sendMessage("enableComparisonDateRange");
    } else {
      this.proxy.sendMessage("disableComparisonDateRange");
    }
  
    goog.analytics.Menu.toggle("f_comparison_button", "f_comparison_menu");
    goog.analytics.Menu.clear("f_comparison_button", "f_comparison_menu");
  },

  addCompareOption: function(value) {
    this.compareOptions.addOption("f_comparison_" + value, value);
  },
  
  setCompareStartValue: function(value) {
    this.compareOptions.setStartValue(value);
    this.compareOptions.reset();
  }
  
}

DateInputView.createDateParser = function(localeString) {
  return this.DateParsers[localeString] || this.DateParsers["en-US"];
}

DateInputView.Parser = function(separator, order, pad, fullYear) {
  this.joinSeparator = separator;
  this.splitSeparator = separator.match(/[^\s]/)
  this.order = order;
  this.pad = pad;
  this.fullYear = fullYear;
}
DateInputView.Parser.prototype = {

  format: function(date) {
    return this["format" + this.order](date);
  },
  
  parse: function(string) {
    return this["parse" + this.order](string);
  },
  
  parseMDY: function(string) {
    var parts = string.split(this.splitSeparator);
    return this.getValidDateOrNull(parts[2], parts[0], parts[1]);
  },
  
  parseDMY: function(string) {
    var parts = string.split(this.splitSeparator);
    return this.getValidDateOrNull(parts[2], parts[1], parts[0]);
  },
  
  parseYMD: function(string) {
    var parts = string.split(this.splitSeparator);
    return this.getValidDateOrNull(parts[0], parts[1], parts[2]);
  },
  
  formatMDY: function(date) {
    var p = this.getDateParts(date);
    return [p.month, p.day, p.year].join(this.joinSeparator);
  },
  
  formatYMD: function(date) {
    var p = this.getDateParts(date);
    return [p.year, p.month, p.day].join(this.joinSeparator);
  },
  
  formatDMY: function(date) {
    var p = this.getDateParts(date);
    return [p.day, p.month, p.year].join(this.joinSeparator);
  },
  
  getDateParts: function(date) {
    var month = date.getMonth() + 1;
    if (month < 10 && this.pad) month = "0" + month;
    var day = date.getDate();
    if (day < 10 && this.pad) day = "0" + day;
    var year = (this.fullYear) ? date.getFullYear() : date.getFullYear() % 100;
    if (year < 10) year = "0" + year;
    return { year: year, month: month, day: day };
  },

  getValidDateOrNull: function(year, month, day) {
    var nYear = Number(year);
    var nMonth = Number(month) - 1;
    var nDay = Number(day);
    if (!isNaN(nYear) && !isNaN(nMonth) && !isNaN(nDay)) {
      if (year.length == 2) {
        nYear += 2000;
      } else if (year.length != 4) {
        return null;
      }
      var date = new Date(nYear, nMonth, nDay);
      if (date.getFullYear() == nYear && 
          date.getMonth() == nMonth && 
          date.getDate() == nDay) {
        return date;
      }
    }
    return null;
  }
  
}
  
DateInputView.DateParsers = {
  
  "en-US": new DateInputView.Parser("/",  "MDY", true,  true),
  "en-GB": new DateInputView.Parser("/",  "DMY", true,  true),
  "fr-FR": new DateInputView.Parser("/",  "DMY", true,  false),
  "it-IT": new DateInputView.Parser("/",  "DMY", true,  false),
  "de-DE": new DateInputView.Parser(".",  "DMY", true,  true),
  "es-ES": new DateInputView.Parser("/",  "DMY", true,  true),
  "nl-NL": new DateInputView.Parser("-",  "DMY", true,  false),
  "pt-BR": new DateInputView.Parser("/",  "DMY", true,  true),
  "da-DK": new DateInputView.Parser("/",  "DMY", true,  true),
  "fi-FI": new DateInputView.Parser(".",  "DMY", false, true),
  "no-NO": new DateInputView.Parser(".",  "DMY", true,  false),
  "sv-SE": new DateInputView.Parser("-",  "YMD", true,  true),
  "ja-JP": new DateInputView.Parser("/",  "YMD", true,  true),
  "ko-KR": new DateInputView.Parser(". ", "YMD", true,  true),
  "zh-CN": new DateInputView.Parser("-",  "YMD", false, true),
  "zh-TW": new DateInputView.Parser("/",  "YMD", false, true),
  "ru-RU": new DateInputView.Parser(".",  "DMY", true,  true)
  
}

DropdownOption = function(id, value) {
  this.element = document.getElementById(id);
  this.value = value;
  this.selected = false;
}

Dropdown = function(id) {
  this.element = document.getElementById(id);
  this.options = [];
  this.selectedValue = 0;
  this.startValue = 0;
}

Dropdown.prototype.addOption = function(id, value) {
  this.options[value] = new DropdownOption(id, value);
}

Dropdown.prototype.setOption = function(value) {
  if (this.selectedValue == value) {
    return;
  }
  if (!value || !this.options[value]) {
    return;
  }
  if (this.startValue == 0) {
    this.startValue = value;
  }

  if (this.selectedValue != 0 && this.options[this.selectedValue]) {
    this.options[this.selectedValue].selected = false;
    if (this.options[value].element) {
      this.options[this.selectedValue].element.className = "";
    }
  }

  this.selectedValue = value;

  this.options[this.selectedValue].selected = true;
  if (this.options[value].element) {
    this.options[this.selectedValue].element.className = "current";
    this.element.innerHTML = this.options[this.selectedValue].element.innerHTML;
  }
}

Dropdown.prototype.setStartValue = function(value) {
  this.startValue = value;
}

Dropdown.prototype.reset = function() {
  this.setOption(this.startValue);
}

Dropdown.prototype.clear = function() {
  this.options = [];
}
